/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package umlapp.elements;

import java.awt.Color;
import java.awt.Graphics;
import java.util.ArrayList;
import umlapp.diagrams.Elements;
import umlapp.elements.members.Attribute;
import umlapp.elements.members.Operation;
import umlapp.elements.members.Visibility;

/**
 *
 * Trieda reprezentujúca elementy typu class.
 *
 * @author Peter Chovanec
 * @author Mario Jaros
 */
public class ClassElement extends AElement implements Elements {

    /**
     * Premenná určujúca viditeľnost triedy.
     */
    private Visibility visibility;
    /**
     * Reťazec vo forme Listu, v ktorom sa uchovávaju všetky atribúty tejto triedy.
     */
    private ArrayList<Attribute> attributes;
    /**
     * Reťazec vo forme Listu, v ktorom sa uchovávaju všetky operácie tejto triedy.
     */
    private ArrayList<Operation> operations;

    /**
     * Konštruktor triedy s dvoma parametrami
     *
     * @param name meno elementu
     * @param dimension dimension elementu
     */
    public ClassElement(String name, Dimension dimension) {
        super(name, dimension);
        this.visibility = Visibility.PUBLIC;
        this.attributes = new ArrayList<>();
        this.operations = new ArrayList<>();
    }

    /**
     * Konštruktor triedy so 4 parametrami
     *
     * @param name meno elementu
     * @param dimension dimension elementu
     * @param attributes list atributov elementu
     * @param operations list operácii elementu
     */
    public ClassElement(String name, Dimension dimension, ArrayList<Attribute> attributes,
            ArrayList<Operation> operations) {
        super(name, dimension);
        this.dimension.width = name.length() * 7 + 30;
        this.dimension.height = 50;
        this.visibility = Visibility.PUBLIC;
        this.attributes = attributes;
        this.operations = operations;
    }

    /**
     * @return vracia visibility
     */
    public Visibility getVisibility() {
        return visibility;
    }

    /**
     * @param visibility nastavuje visibility
     */
    public void setVisibility(Visibility visibility) {
        this.visibility = visibility;
    }

    /**
     * Metoda na ziskanie atributov
     *
     * @return list attributes
     */
    public ArrayList<Attribute> getAttributes() {
        return attributes;
    }

    /**
     * Nastvuje atribúty elementu
     *
     * @param attributes atributy
     */
    public void setAttributes(ArrayList<Attribute> attributes) {
        this.attributes = attributes;
    }

    /**
     * Ziskanie operácii elementu
     *
     * @return operácie
     */
    public ArrayList<Operation> getOperations() {
        return operations;
    }

    /**
     * Nastavuje operácie elementu
     *
     * @param operations
     */
    public void setOperations(ArrayList<Operation> operations) {
        this.operations = operations;
    }

    /**
     * Metoda na vykreslovanie elementu
     *
     * @param g
     */
    @Override
    public void drawElement(Graphics g) {
        dimension.width = getTheLongestName() * 7 + 38;
        dimension.height = attributes.size() * 15 + operations.size() * 15 + 45;
        drawElementaryElement(g);
        drawName(g);
        drawAttributes(g);
        drawOperations(g);
    }

    /**
     * Vykresluje zakladny obdlznik so vsetkymi ciarami.
     */
    public void drawElementaryElement(Graphics g) {
        g.setColor(Color.CYAN);
        g.fillRect(dimension.x, dimension.y, dimension.width, dimension.height);
        g.setColor(Color.BLACK);
        g.drawRect(dimension.x - 1, dimension.y - 1, dimension.width + 1, dimension.height + 1);
        g.drawLine(
                dimension.x,
                dimension.y + 15,
                dimension.x + dimension.width,
                dimension.y + 15);
        g.drawLine(
                dimension.x,
                dimension.y + 30 + attributes.size() * 15,
                dimension.x + dimension.width,
                dimension.y + 30 + attributes.size() * 15);
    }

    /**
     * Napise meno triedy priblizne do stredu vertikalne.
     *
     */
    public void drawName(Graphics g) {
        int x = (dimension.x + (dimension.width / 2)) - (7 * (name.length() / 2));
        int y = dimension.y + 12;
        g.setColor(Color.BLACK);
        g.drawString(name, x, y);
    }

    /**
     * Napise atributy, ale nie do stredu ale od zaciatku tak ako je v PowerDesigner.
     */
    public void drawAttributes(Graphics g) {
        for (int i = 0; i < attributes.size(); i++) {
            Attribute attribute = attributes.get(i);
            String lName = attribute.getVisibility().MARK + " " + attribute.getName() + "  :" + attribute.getDataType();
            g.drawString(
                    lName,
                    dimension.x + 3,
                    dimension.y + 27 + (15 * i));
        }
    }

    /**
     * Podobne ako drawAttributes().
     */
    public void drawOperations(Graphics g) {
        for (int i = 0; i < operations.size(); i++) {
            Operation operation = operations.get(i);
            String lName = operation.getVisibility().MARK
                    + " "
                    + operation.getName()
                    + "()  :"
                    + operation.getReturnDataType();
            g.drawString(
                    lName,
                    dimension.x + 3,
                    dimension.y + 42 + (15 * attributes.size()) + (15 * i));
        }
    }

    /**
     * Vrati velkost najdhsieho stringu, kontroluje aj ci su polia atributov a operacii prazdne. Ak
     * su tak hladanie preskakuje a vracia hodnotu nazvu triedy.
     */
    public int getTheLongestName() {
        Attribute bestAttribute = null;
        Operation bestOperation = null;
        if (!attributes.isEmpty()) {
            bestAttribute = attributes.get(0);
            for (int i = 0; i < attributes.size(); i++) {
                Attribute pomAttribute = attributes.get(i);
                if ((bestAttribute.getName().length() + bestAttribute.getDataType().length()) < (pomAttribute.getName().length() + pomAttribute.getDataType().length())) {
                    bestAttribute = pomAttribute;
                }
            }
        }
        if (!operations.isEmpty()) {
            bestOperation = operations.get(0);
            for (int i = 0; i < operations.size(); i++) {
                Operation pomOperation = operations.get(i);
                if ((bestOperation.getName().length() + bestOperation.getReturnDataType().length()) < (pomOperation.getName().length() + pomOperation.getReturnDataType().length())) {
                    bestOperation = pomOperation;
                }
            }
        }
        if ((bestAttribute == null) && (bestOperation == null)) {
            return name.length();
        }
        if ((bestAttribute != null) && (bestOperation == null)) {
            return bestAttribute.getName().length() + bestAttribute.getDataType().length();
        }
        if ((bestAttribute == null) && (bestOperation != null)) {
            return bestOperation.getName().length() + bestOperation.getReturnDataType().length();
        }
        if ((bestAttribute != null) && (bestOperation != null)) {
            if (bestAttribute.getName().length() >= bestOperation.getName().length()) {
                return bestAttribute.getName().length() + bestAttribute.getDataType().length();
            } else {
                return bestOperation.getName().length() + bestOperation.getReturnDataType().length();
            }
        }
        return 0;
    }
}
